package com.wuwei.poi.ppt;

import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xslf.usermodel.*;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.io.*;
import java.util.List;

public class PPTX {

    // 转换系数
    public static final double POINTS_PER_CM = 28.3465;
    public static void editPPTX(String inputFilePath) throws Exception {
        String outputFilePath = inputFilePath.replace("3、M8培训课件", "M8-TA课件");
        String title = inputFilePath.substring(inputFilePath.lastIndexOf("\\")+1,inputFilePath.lastIndexOf("."));
        try (
                FileInputStream fis = new FileInputStream(inputFilePath);
                XMLSlideShow ppt = new XMLSlideShow(fis)
        ) {

            addSilde(ppt, title);
//
//            copySlide(ppt, 0, 1);
//            copySlide(ppt, 1, 2);
//            copySlide(ppt, 2, ppt.getSlides().size()-1);

            // 保存文件
            try (FileOutputStream out = new FileOutputStream(outputFilePath)) {
                ppt.write(out);
            }
        }
    }


    /**
     * 从模板PPT (PPT_PATH) 中复制指定索引的幻灯片，并将其插入到目标ppt的指定位置。
     *
     * @param ppt    目标演示文稿对象
     * @param index1 要从模板PPT中复制的幻灯片的索引 (0-based)
     * @param index2 要将幻灯片插入到目标PPT中的位置索引 (0-based)
     * @throws IOException              如果读取模板文件失败
     * @throws IndexOutOfBoundsException 如果提供的索引无效
     */
    private static void copySlide(XMLSlideShow ppt, int index1, int index2) throws IOException {
        // 1. 使用 try-with-resources 语句确保源PPT文件能被自动关闭
        try (FileInputStream is = new FileInputStream(PPT_PATH);
             XMLSlideShow sourcePpt = new XMLSlideShow(is)) {
            // 2. 【输入校验】检查源索引 (index1) 是否有效
            if (index1 < 0 || index1 >= sourcePpt.getSlides().size()) {
                throw new IndexOutOfBoundsException("源幻灯片索引 " + index1 + " 无效。模板PPT中只有 "
                        + sourcePpt.getSlides().size() + " 张幻灯片。");
            }
            // 3. 【输入校验】检查目标索引 (index2) 是否有效
            // index2 可以等于当前幻灯片数量，表示插入到末尾
            if (index2 < 0 || index2 > ppt.getSlides().size()) {
                throw new IndexOutOfBoundsException("目标位置索引 " + index2 + " 无效。当前PPT中有 "
                        + ppt.getSlides().size() + " 张幻灯片，有效插入范围是 0 到 " + ppt.getSlides().size() + "。");
            }
            // 4. 获取指定的源幻灯片
            XSLFSlide sourceSlide = sourcePpt.getSlides().get(index1);
            // 5. 找到或创建一个合适的幻灯片版式 (Layout)
            // 这部分逻辑与之前相同，对于保证样式一致性至关重要
            XSLFSlideLayout sourceLayout = sourceSlide.getSlideLayout();
            XSLFSlideMaster sourceMaster = sourceLayout.getSlideMaster();
            XSLFSlideLayout destinationLayout = findOrCreateMatchingLayout(ppt, sourceLayout);
            if (destinationLayout!=null) {
                // 6. 在目标PPT中创建一张新的幻灯片（默认会添加到末尾）
                XSLFSlide newSlide = ppt.createSlide(destinationLayout);
                // 7. 【核心步骤】将源幻灯片的所有内容复制到新幻灯片中
                newSlide.importContent(sourceSlide);

                // 8. 【关键步骤】将新创建的幻灯片移动到指定的位置 (index2)
                ppt.setSlideOrder(newSlide, index2);
                System.out.println("成功从 '" + PPT_PATH + "' 的位置 " + index1 + " 复制幻灯片到当前PPT的位置 " + index2);
            } else {
                System.out.println(index1);
                System.out.println(index2);
            }
        }
    }
    /**
     * 辅助方法：在目标PPT中查找或创建与源版式匹配的版式。
     * @param targetPpt 目标PPT
     * @param sourceLayout 源版式
     * @return 在目标PPT中可用的版式
     * @throws IOException 如果导入母版失败
     */
    private static XSLFSlideLayout findOrCreateMatchingLayout(XMLSlideShow targetPpt, XSLFSlideLayout sourceLayout) throws IOException {
        // 尝试在目标PPT中根据名称找到匹配的母版和版式
        for (XSLFSlideMaster master : targetPpt.getSlideMasters()) {
            XSLFSlideLayout layout = master.getLayout(sourceLayout.getType());
            if (layout != null) {
                return layout; // 找到了完全匹配的版式
            }
        }

        return null;
    }

    public static final String PPT_PATH = "D:\\uploads\\OneDrive\\幻灯片模板\\模板.pptx";

    private static void addSilde(XMLSlideShow ppt, String title) throws IOException {
        String imagePath = "C:\\Users\\84206\\Desktop\\background.jpg";
        Dimension pageSize = ppt.getPageSize();
        // 创建新幻灯片
        XSLFSlide newSlide = ppt.createSlide();
        addImages(ppt, newSlide,pageSize.height,pageSize.width,imagePath);

        addText(
                newSlide,                   // 目标幻灯片
                title,                      // 文本内容
                0.97 * POINTS_PER_CM,//x坐标
                6.38 * POINTS_PER_CM,               //  坐标 (Points)
                31.82 * POINTS_PER_CM,//宽度,
                2.29 * POINTS_PER_CM,      // 高度 (Points)
                VerticalAlignment.MIDDLE,   // 垂直居中
                TextAlign.CENTER,           // 水平居中
                "微软雅黑",                 // 字体
                54.0,                       // 字号
                Color.WHITE.getRGB(),       // 字体颜色 (白色)
                true                        // 加粗
        );

        addText(
                newSlide,                   // 目标幻灯片
                "模块：\n学时:",                      // 文本内容
                0.97 * POINTS_PER_CM,//x坐标
                10.17 * POINTS_PER_CM,               // y 坐标 (Points)
                14.6 * POINTS_PER_CM,//宽度,
                2.31 * POINTS_PER_CM,      //高度 (Points)
                VerticalAlignment.MIDDLE,   // 垂直居中
                TextAlign.LEFT,           // 水平居中
                "微软雅黑",                 // 字体
                24.0,                       // 字号
                Color.WHITE.getRGB(),       // 字体颜色 (白色)
                true                        // 加粗
        );

        addText(
                newSlide,                   // 目标幻灯片
                "课件编号：\n课件版本:",                      // 文本内容
                0.97 * POINTS_PER_CM,//x坐标
                12.77 * POINTS_PER_CM,               // y 坐标 (Points)
                14.6 * POINTS_PER_CM,//宽度,
                2.31 * POINTS_PER_CM,      //高度 (Points)
                VerticalAlignment.MIDDLE,   // 垂直居中
                TextAlign.LEFT,           // 水平居中
                "黑体",                 // 字体
                20.0,                       // 字号
                Color.WHITE.getRGB(),       // 字体颜色 (白色)
                true                        // 加粗
        );

        addText(
                newSlide,                   // 目标幻灯片
                "2025年10月9日",                      // 文本内容
                8.27 * POINTS_PER_CM,//x坐标
                16.01 * POINTS_PER_CM,               // y 坐标 (Points)
                17.06 * POINTS_PER_CM,//宽度,
                1.28 * POINTS_PER_CM,      //高度 (Points)
                VerticalAlignment.MIDDLE,   // 垂直居中
                TextAlign.CENTER,           // 水平居中
                "黑体",                 // 字体
                18.0,                       // 字号
                Color.WHITE.getRGB(),       // 字体颜色 (白色)
                true                        // 加粗
        );

        // 将新的幻灯片移动到最前面
        ppt.setSlideOrder(newSlide, 0);
    }

    /**
     * 添加文本框 (单位：Points)
     *
     * @param slide               幻灯片
     * @param text                文本框文字
     * @param x                   横坐标（Points）
     * @param y                   纵坐标（Points）
     * @param width               宽度（Points）
     * @param height              高度（Points）
     * @param verticalAlignment   垂直对齐方式（来自 VerticalAlignment 枚举）
     * @param horizontalAlignment 水平对齐方式（来自 TextAlign 枚举）
     * @param fontName            字体名称
     * @param fontSize            字体大小（Points）
     * @param fontColor           字体颜色（RGB int 值）
     * @param isBold              是否加粗
     */
    private static void addText(XSLFSlide slide, String text, double x, double y, double width, double height,
                                VerticalAlignment verticalAlignment, TextAlign horizontalAlignment,
                                String fontName, double fontSize, int fontColor, boolean isBold) {


        XSLFTextBox textBox = slide.createTextBox();

        // ==================== 修改部分：直接使用 Points 设置 Anchor ====================
        // setAnchor 方法接收一个 Rectangle2D 对象，其单位就是 Points。
        // 无需手动转换为 EMUs。
        textBox.setAnchor(new Rectangle2D.Double(x, y, width, height));
        // ==========================================================================

        textBox.setVerticalAlignment(verticalAlignment);

        // 获取或创建段落
        XSLFTextParagraph paragraph = textBox.getTextParagraphs().isEmpty() ?
                textBox.addNewTextParagraph() :
                textBox.getTextParagraphs().getFirst();

        paragraph.setTextAlign(horizontalAlignment);

        XSLFTextRun textRun = paragraph.addNewTextRun();
        textRun.setText(text);
        textRun.setFontFamily(fontName);
        textRun.setFontSize(fontSize);
        textRun.setFontColor(new Color(fontColor));
        textRun.setBold(isBold); // 使用 boolean 更清晰

    }

    /**
     * 添加图片
     *
     * @param ppt
     * @param newSlide
     * @param height 图片高度
     * @param width 图片宽度
     * @throws IOException
     */
    private static void addImages(XMLSlideShow ppt, XSLFSlide newSlide,int height,int width,String imagePath) throws IOException {


        byte[] pictureData;
        try (InputStream is = new FileInputStream(imagePath)) {
            pictureData = IOUtils.toByteArray(is);
        }

        PictureData pd = ppt.addPicture(pictureData, PictureData.PictureType.JPEG);
        XSLFPictureShape picture = newSlide.createPicture(pd);
        picture.setAnchor(new Rectangle(0, 0, width, height));
    }
}
